package com.ywu.data.source.standard.source.jdbc;

import com.ywu.boot.exception.YwuRuntimeException;
import com.ywu.common.gson.GsonUtils;
import com.ywu.data.source.standard.config.YwuDataSourceConfig;
import com.ywu.data.source.standard.dto.YwuDataExecComplexQueryFieldDto;
import com.ywu.data.source.standard.dto.YwuDataExecComplexQueryPageDto;
import com.ywu.data.source.standard.dto.YwuExecCommonParamDto;
import com.ywu.data.source.standard.entity.YwuDataExecEntity;
import com.ywu.data.source.standard.source.sql.YwuPrepareSqlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.sql.*;
import java.util.*;

/**
 * @ClassName JdbcUtil
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/10/26 10:46
 * @Version 1.0
 **/
@Component
@Slf4j
public class JdbcUtil {
    @Autowired
    private YwuDataSourceConfig config;

    @Autowired
    private YwuPrepareSqlUtil ywuPrepareSqlUtil;

    private final Map<String, List<Connection>> connectionMap = new HashMap<>();

    private final Map<String, JdbcParamEntity> paramEntityMap = new HashMap<>();

    @PostConstruct
    public void initDriver() {
        String paramInfo = config.getJdbcParam();
        Map<String, Object> deserialize = GsonUtils.deserialize(paramInfo, Map.class);
        Set<String> keys = deserialize.keySet();
        for (String key : keys) {
            Object o = deserialize.get(key);
            String serialize = GsonUtils.serialize(o);
            JdbcParamEntity entity = GsonUtils.deserialize(serialize, JdbcParamEntity.class);
            paramEntityMap.put(key, entity);
            try {
                Class.forName(entity.getJdbcDriver());
            } catch (ClassNotFoundException e) {
                log.error("driver load error {}", entity.getJdbcDriver());
            }
        }
    }

    /**
    * @Author GroundDemo
    * @Description 获取jdbc连接
    * @Date 11:23 2024/10/26
    * @Param [dataSourceType, dataSourceName]
    * @return java.sql.Connection
    **/
    public Connection getConnect(String dataSourceType, String dataSourceName) {
        if (!paramEntityMap.containsKey(dataSourceType)) {
            throw new YwuRuntimeException("get connect error! no data source type");
        }
        // 替换dataSourceName
        JdbcParamEntity jdbcParamEntity = paramEntityMap.get(dataSourceType);
        String jdbcUser = jdbcParamEntity.getJdbcUser();
        String jdbcPassword = jdbcParamEntity.getJdbcPassword();
        String jdbcUrl = jdbcParamEntity.getJdbcUrl();
        jdbcUrl = jdbcUrl.replace("ywu_data_source_name", dataSourceName);
        String mapKey = dataSourceType + "-" + dataSourceName;
        try {
            // 构建连接池
            if (!connectionMap.containsKey(mapKey)) {
                ArrayList<Connection> connections = new ArrayList<>();
                for (int i = 0; i < jdbcParamEntity.getPoolSize(); i++) {
                    connections.add(DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword));
                }
                connectionMap.put(mapKey, connections);
            }
        } catch (SQLException e) {
            log.error("get connect error {}", e.getMessage());
        }
        // 根据集合大小生成随机下标
        int randomIntInRange = new Random().nextInt(jdbcParamEntity.getPoolSize());
        // 获取对应下标下的连接
        List<Connection> connections = connectionMap.get(mapKey);
        return connections.get(randomIntInRange);
    }

    /**
    * @Author GroundDemo
    * @Description 创建数据源
    * @Date 16:12 2024/10/26
    * @Param [connect, createDataSourceSql]
    * @return void
    **/
    public void execDataSource(Connection connect, String createDataSourceSql) {
        try {
            PreparedStatement statement = connect.prepareStatement(createDataSourceSql);
            statement.execute();
        } catch (SQLException e) {
            log.error("prepare statement error {}", e.getMessage());
            throw new YwuRuntimeException("create prepare statement error");
        }
    }

    /**
    * @Author GroundDemo
    * @Description 执行增删改
    * @Date 14:44 2024/11/20
    * @Param [connect, createDataSourceSql, type, ywuDataExecEntity]
    * @return void
    **/
    public void execSql(Connection connect, String createDataSourceSql, String type, YwuDataExecEntity ywuDataExecEntity) {
        try {
            PreparedStatement statement = connect.prepareStatement(createDataSourceSql);
            switch (type) {
                case "INSERT":
                    ywuPrepareSqlUtil.prepareInsertSql(ywuDataExecEntity, statement);
                    break;
                case "UPDATE":
                    ywuPrepareSqlUtil.prepareUpdateSql(ywuDataExecEntity, statement);
                    break;
                case "DELETE":
                    ywuPrepareSqlUtil.prepareDeleteSql(ywuDataExecEntity, statement);
                    break;
            }
            statement.execute();
        } catch (SQLException e) {
            log.error("prepare statement error {}", e.getMessage());
            throw new YwuRuntimeException("create prepare statement error");
        }
    }

    /**
    * @Author GroundDemo
    * @Description 实行查询操作并封装数据结果
    * @Date 17:27 2024/11/20
    * @Param [connect, createDataSourceSql, ywuDataExecEntity]
    * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
    **/
    public List<Map<String, Object>> execQuery(Connection connect, String createDataSourceSql, YwuDataExecEntity ywuDataExecEntity) {
        try {
            log.debug("exec query sql is {} param = {}", createDataSourceSql, ywuDataExecEntity.getConditionParam());
            PreparedStatement statement = connect.prepareStatement(createDataSourceSql);
            // 构建查询参数
            int index = 1;
            List<YwuExecCommonParamDto> conditionParam = ywuDataExecEntity.getConditionParam();
            // 条件字段配置的时候才需要进行参数预处理，没有配置的时候不需要预处理
            if (!StringUtils.isEmpty(ywuDataExecEntity.getConditionFields())) {
                String[] conditionFieldArray = ywuDataExecEntity.getConditionFields().split(",");
                index = ywuPrepareSqlUtil.prepareCondition(conditionFieldArray, conditionParam, index, statement);
            }
            // 执行查询
            ResultSet resultSet = statement.executeQuery();
            // 封装结果
            return doResult(resultSet, ywuDataExecEntity);
        } catch (SQLException e) {
            log.error("prepare statement error {}", e.getMessage());
            throw new YwuRuntimeException("create prepare statement error");
        }
    }

    /**
    * @Author GroundDemo
    * @Description 封装查询结果集
    * @Date 17:30 2024/11/20
    * @Param [resultSet, ywuDataExecEntity]
    * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
    **/
    private List<Map<String, Object>> doResult(ResultSet resultSet, YwuDataExecEntity ywuDataExecEntity) throws SQLException {
        List<Map<String, Object>> res = new ArrayList<>();
        // 根据字段获取rs中的数据
        List<String> execFields = ywuDataExecEntity.getExecFields();
        while (resultSet.next()) {
            HashMap<String, Object> map = new HashMap<>();
            for (int index = 0; index < execFields.size(); index++) {
                Object object = resultSet.getObject(index + 1);
                map.put(execFields.get(index), object);
            }
            res.add(map);
        }
        return res;
    }

    /**
    * @Author GroundDemo
    * @Description 执行复杂查询
    * @Date 15:55 2025/9/13
    * @Param [connect, execSql, ywuDataExecEntity]
    * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
    **/
    public List<Map<String, Object>> execComplexQuery(Connection connect, String execSql, YwuDataExecEntity ywuDataExecEntity) {
        try {
            log.debug("exec query sql is {} conditionParam = {} groupConditionParam = {} pageInfo = {}", execSql,
                    ywuDataExecEntity.getConditionParam(), ywuDataExecEntity.getGroupConditionParam(), ywuDataExecEntity.getPageFields());
            PreparedStatement statement = connect.prepareStatement(execSql);
            // 构建查询参数
            int index = 1;
            List<YwuExecCommonParamDto> conditionParam = ywuDataExecEntity.getConditionParam();
            // 条件字段配置的时候才需要进行参数预处理，没有配置的时候不需要预处理
            if (!StringUtils.isEmpty(ywuDataExecEntity.getConditionFields())) {
                String[] conditionFieldArray = ywuDataExecEntity.getConditionFields().split(",");
                index = ywuPrepareSqlUtil.prepareCondition(conditionFieldArray, conditionParam, index, statement);
            }
            // 构建分组字段参数
            List<YwuExecCommonParamDto> groupConditionParam = ywuDataExecEntity.getGroupConditionParam();
            if (!StringUtils.isEmpty(ywuDataExecEntity.getGroupConditionFields())) {
                String[] groupFieldArray = ywuDataExecEntity.getGroupConditionFields().split(",");
                index = ywuPrepareSqlUtil.prepareCondition(groupFieldArray, groupConditionParam, index, statement);
            }
            // 构建分页字段参数
            if (ywuDataExecEntity.getEnablePageInfo()) {
                YwuDataExecComplexQueryPageDto pageFields = ywuDataExecEntity.getPageFields();
                // 构建起始位置
                int pageStart = Integer.parseInt(pageFields.getPageNumber());
                int pageSize = Integer.parseInt(pageFields.getPageSize());
                int limitStart = (pageStart - 1) * pageSize;
                statement.setObject(index, limitStart);
                statement.setObject(index + 1, pageSize);
            }
            // 执行查询
            ResultSet resultSet = statement.executeQuery();
            // 封装结果
            return doComplexResult(resultSet, ywuDataExecEntity);
        } catch (SQLException e) {
            log.error("prepare statement error {}", e.getMessage());
            throw new YwuRuntimeException("create prepare statement error");
        }
    }

    /**
    * @Author GroundDemo
    * @Description 封装复杂查询结果集
    * @Date 16:41 2025/9/13
    * @Param [resultSet, ywuDataExecEntity]
    * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
    **/
    private List<Map<String, Object>> doComplexResult(ResultSet resultSet, YwuDataExecEntity ywuDataExecEntity) throws SQLException {
        List<Map<String, Object>> res = new ArrayList<>();
        // 根据字段获取rs中的数据
        List<YwuDataExecComplexQueryFieldDto> execFiledList = GsonUtils.deserializeList(ywuDataExecEntity.getComplexQueryFieldListStr(), YwuDataExecComplexQueryFieldDto.class);
        while (resultSet.next()) {
            HashMap<String, Object> map = new HashMap<>();
            for (int index = 0; index < execFiledList.size(); index++) {
                Object object = resultSet.getObject(index + 1);
                if (StringUtils.isEmpty(execFiledList.get(index).getAlias())) {
                    map.put(execFiledList.get(index).getFieldName(), object);
                } else {
                    map.put(execFiledList.get(index).getAlias(), object);
                }
            }
            res.add(map);
        }
        return res;
    }
}
